package rs.udd.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import rs.udd.exceptions.UddException;
import rs.udd.model.Admin;
import rs.udd.model.Advert;
import rs.udd.model.Advertiser;
import rs.udd.model.Agent;
import rs.udd.model.Link;
import rs.udd.repository.AdminRepository;
import rs.udd.repository.AdvertiserRepository;
import rs.udd.repository.AgentRepository;
import rs.udd.repository.LinkRepository;
import rs.udd.service.document.indexer.IndexManager;
import rs.udd.service.dto.user.AdminChangePasswordDto;
import rs.udd.service.dto.user.DeleteUserDto;
import rs.udd.service.util.FileUtil;

@Service
@Transactional
public class AdminServiceImpl implements AdminService {

	private static final Logger LOGGER = LogManager.getLogger(AdminServiceImpl.class);
	
	@Resource
	private AdminRepository adminRepository;

	@Resource
	private AgentRepository agentRepository;

	@Resource
	private AdvertiserRepository advertiserRepository;
	
	@Resource
	private LinkRepository linkRepository;

	@Autowired
	private MailService mailService;
	
	@Autowired
	private PasswordEncoder encoder;
	
	@Override
	public Admin save(Admin admin) throws UddException {
		try {
			return adminRepository.save(admin);
		} catch (Exception e) {
			throw new UddException("Udd exception", e);
		}
	}

	@Override
	public void delete(Long id) throws UddException {
		try {
			adminRepository.delete(id);
		} catch (Exception e) {
			throw new UddException("Udd exception", e);
		}
	}

	@Override
	public List<Admin> findAll() throws UddException {
		try {
			return adminRepository.findAll();
		} catch (Exception e) {
			throw new UddException("Udd exception", e);
		}
	}

	@Override
	public Admin findOne(Long id) throws UddException {
		try {
			return adminRepository.findOne(id);
		} catch (Exception e) {
			throw new UddException("Udd exception", e);
		}
	}

	@Override
	public void deleteAgent(DeleteUserDto dto) throws UddException {
		try {
			Agent agent = agentRepository.findOne(dto.getId());
			String documentId = agent.getIndexedDocumentId();
			
			if (StringUtils.isNotEmpty(documentId)) {
				IndexManager.getIndexer().deleteDocument(documentId);

				String folderWithCv = agent.getFolderWithCv();
				FileUtil.cleanFile(folderWithCv);
			}
			
			String email = agent.getEmail();
			agentRepository.delete(agent.getId());
			
			String reason = "Your account has been deleted.\nReason: " + dto.getReason(); 
			mailService.sendMail(email, "Deletion", reason);
		} catch (Exception e) {
			LOGGER.error("Exception", e);
			throw new UddException(e.getMessage());
		}
	}

	@Override
	public void deleteAdvertiser(DeleteUserDto dto) throws UddException {
		try {
			Advertiser advertiser = advertiserRepository.findOne(dto.getId());
			Set<Advert> adverts = advertiser.getAdverts();
			for (Advert advert : adverts) {
				String documentId = advert.getIndexedDocumentId();
				
				if (StringUtils.isNotEmpty(documentId)) {
					IndexManager.getIndexer().deleteDocument(documentId);
					FileUtil.cleanFile(advert.getFilePath());
				}
			}
			
			Link link = linkRepository.findByAdvertiser(advertiser);
			if (link != null) {
				linkRepository.delete(link);
			}
			
			String email = advertiser.getEmail();
			advertiserRepository.delete(advertiser.getId());
			
			String reason = "Your account has been deleted.\nReason: " + dto.getReason(); 
			mailService.sendMail(email, "Deletion", reason);
		} catch (Exception e) {
			LOGGER.error("Exception", e);
			throw new UddException(e.getMessage());
		}
	}

	@Override
	public List<Advertiser> getAllAdvertisers() {
		return advertiserRepository.findAll();
	}

	@Override
	public List<Advertiser> getAllInactiveAdvertisers() {
		List<Advertiser> allAdvertisers = advertiserRepository.findAll();
		List<Advertiser> result = new ArrayList<Advertiser>(allAdvertisers.size());
		for (Advertiser advertiser : allAdvertisers) {
			if (!advertiser.isEnabled() || !advertiser.getEmailActive()) {
				result.add(advertiser);
			}
		}
		return result;
	}

	@Override
	public List<Agent> getAllAgents() {
		return agentRepository.findAll();
	}

	@Override
	public void changeAgentPassword(AdminChangePasswordDto dto) {
		Agent agent = agentRepository.findOne(dto.getUsersId());
		String newRawPassword = dto.getNewPassword();
		String newEncodedPasword = encoder.encode(newRawPassword);
		
		agent.setPassword(newEncodedPasword);
		agentRepository.save(agent);

		String to = agent.getEmail();
		sendPasswordChangeEmail(to, newRawPassword);
	}

	@Override
	public void changeAdvertiserPassword(AdminChangePasswordDto dto) {
		Advertiser advertiser = advertiserRepository.findOne(dto.getUsersId());
		String newRawPassword = dto.getNewPassword();
		String newEncodedPasword = encoder.encode(newRawPassword);

		advertiser.setPassword(newEncodedPasword);
		advertiserRepository.save(advertiser);
		
		String to = advertiser.getEmail();
		sendPasswordChangeEmail(to, newRawPassword);		
	}
	
	private void sendPasswordChangeEmail(String to, String newRawPassword) {
		String body = "Your password has been changed. New password is: " + newRawPassword;
		mailService.sendMail(to, "Password change", body);
	}
	
}
